//
//  WCBuildTargetGetInfoWindowController.m
//  WabbitCode
//
//  Created by William Towe on 4/2/09.
//  Copyright 2009 Revolution Software. All rights reserved.
//

#import "WCBuildTargetGetInfoWindowController.h"
#import "WCProject.h"
#import "WCBuildTarget.h"
#import "WCMacros.h"
#import "WCBuildConfiguration.h"
#import "NSDictionary+WCExtensions.h"
#import "NSPopUpButton+WCExtensions.h"
#import "WCIconAndTextFieldCell.h"
#import "NSArrayController+WCExtensions.h"
#import "WCEditIncludeDirectoriesSheetController.h"
#import "WCAppController.h"
#import "WCBuildDefine.h"
#import "WCEditDefinesSheetController.h"
#import "WCNewStepSheetController.h"


NSString *kWCBuildTargetGetInfoWindowGeneralTabIdentifier = @"General";
NSString *kWCBuildTargetGetInfoWindowBuildOptionsTabIdentifier = @"Build Options";
NSString *kWCBuildTargetGetInfoWindowBuildStepsTabIdentifier = @"Build Steps";
NSString *kWCBuildTargetGetInfoWindowConfigurationsTabIdentifier = @"Configurations";

#define kWCBuildTargetGetInfoConfigurationsNameColumnIdentifier @"Name"
#define kWCBuildTargetGetInfoBuildOptionsOptionColumnIdentifier @"Option"
#define kWCBuildTargetGetInfoBuildOptionsValueColumnIdentifier @"Value"

@interface WCBuildTargetGetInfoWindowController (Private)
- (void)_updateConfigurationsPopUpButton;
@end

@implementation WCBuildTargetGetInfoWindowController
#pragma mark -
#pragma mark *** Subclass Overrides ***
- (void)dealloc {
#ifdef WCDEBUG
	NSLog(@"WCBuildTargetGetInfoWindowController dealloc");
#endif
	[[NSNotificationCenter defaultCenter] removeObserver:self];
	
	[_buildTarget release];
	[_selectedBuildConfigurationOptionNames release];
	[super dealloc];
}

- (void)windowDidLoad {
	[super windowDidLoad];
	
	if (!NSIsEmptyRect([[self buildTarget] getInfoWindowFrame]))
		[[self window] setFrame:[[self buildTarget] getInfoWindowFrame] display:NO];
	
	static NSDictionary *_newProjectModelsDict = nil;
	if (!_newProjectModelsDict) {
		_newProjectModelsDict = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"NewProjectModels" ofType:@"plist"]];
	}
	
	[_buildOptionsTableView setTarget:self];
	[_buildOptionsTableView setDoubleAction:@selector(_buildOptionsTableViewDoubleAction:)];
	
	[_buildStepsTableView setTarget:self];
	[_buildStepsTableView setDoubleAction:@selector(_buildStepsTableViewDoubleAction:)];
	
	// set up the target model pop up button
	for (NSDictionary *mDict in [_newProjectModelsDict objectForKey:@"models"]) {
		NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:[mDict objectForKey:@"name"] action:[_modelPopUpButton action] keyEquivalent:@""] autorelease];
		[item setTag:[mDict unsignedIntegerForKey:@"model"]];
		[item setRepresentedObject:[mDict objectForKey:@"outputs"]];
		[[_modelPopUpButton menu] addItem:item];
	}
	[_modelPopUpButton selectItemWithTag:[[self buildTarget] targetModel]];
	
	// set up the target output type pop up button
	for (NSDictionary *oDict in [[_modelPopUpButton selectedItem] representedObject]) {
		NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:[oDict objectForKey:@"name"] action:[_outputPopUpButton action] keyEquivalent:@""] autorelease];
		[item setTag:[oDict unsignedIntegerForKey:@"output"]];
		[[_outputPopUpButton menu] addItem:item];
	}
	[_outputPopUpButton selectItemWithTag:[[self buildTarget] targetOutputType]];
	
	// set up the configurations pop up button
	for (WCBuildConfiguration *config in [[self buildTarget] buildConfigurations]) {
		NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:[config name] action:[_configurationPopUpButton action] keyEquivalent:@""] autorelease];
		[item setImage:[config icon]];
		[item setRepresentedObject:config];
		[[_configurationPopUpButton menu] addItem:item];
		
		[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_buildConfigurationNameDidChangeNotification:) name:kWCBCBuildConfigurationNameDidChangeNotification object:config];
	}
	[_configurationPopUpButton selectItemWithRepresentedObject:[[self buildTarget] activeBuildConfiguration]];
	[self setSelectedBuildConfigurationOptionNames:[[[self buildTarget] activeBuildConfiguration] arrayOfOptionNames]];
	
	[_buildOptionsTableView reloadData];
	
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_activeBuildConfigurationDidChangeNotification:) name:kWCBTActiveBuildConfigurationDidChangeNotification object:[self buildTarget]];
}

- (NSString *)windowTitleForDocumentDisplayName:(NSString *)displayName {
	[[self window] setRepresentedFilename:@""];
	return [NSString stringWithFormat:NSLocalizedString(@"Target \"%@\" Info",@"build target get info window title"), [[self buildTarget] name]];
}
#pragma mark NSWindow Delegate
- (void)windowDidResize:(NSNotification *)note {
	[[self buildTarget] setGetInfoWindowFrame:[[note object] frame]];
}

- (void)windowDidMove:(NSNotification *)note {
	[[self buildTarget] setGetInfoWindowFrame:[[note object] frame]];
}
#pragma mark NSControl Delegate
- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor {
	return ([[fieldEditor string] length])?YES:NO;
}
#pragma mark NSTableView Delegate
- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
	if ([[tableColumn identifier] isEqualToString:kWCBuildTargetGetInfoBuildOptionsOptionColumnIdentifier]) {
		NSTextFieldCell *cell = [[[NSTextFieldCell alloc] init] autorelease];
		
		[cell setControlSize:NSSmallControlSize];
		[cell setLineBreakMode:NSLineBreakByTruncatingTail];
		[cell setFont:[NSFont controlContentFontOfSize:[NSFont systemFontSizeForControlSize:[cell  controlSize]]]];
		
		return cell;
	}
	else if ([[tableColumn identifier] isEqualToString:kWCBuildTargetGetInfoBuildOptionsValueColumnIdentifier]) {
		return [[self selectedBuildConfiguration] cellForOptionName:[[self selectedBuildConfigurationOptionNames] objectAtIndex:row]];
	}
	return nil;
}

- (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
	if ([[tableColumn identifier] isEqualToString:kWCBuildTargetGetInfoBuildOptionsValueColumnIdentifier]) {
		return ([[[self selectedBuildConfigurationOptionNames] objectAtIndex:row] isEqualToString:kWCBCDefinesOptionName] || [[[self selectedBuildConfigurationOptionNames] objectAtIndex:row] isEqualToString:kWCBCIncludeDirectoriesOptionName])?NO:YES;
	}
	return YES;
}
#pragma mark NSTableViewDataSource Protocol
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
	return [[self selectedBuildConfiguration] numberOfOptions];
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
	if ([[tableColumn identifier] isEqualToString:kWCBuildTargetGetInfoBuildOptionsOptionColumnIdentifier]) {
		return [[self selectedBuildConfigurationOptionNames] objectAtIndex:row];
	}
	else if ([[tableColumn identifier] isEqualToString:kWCBuildTargetGetInfoBuildOptionsValueColumnIdentifier]) {
		return [[self selectedBuildConfiguration] valueForOptionName:[[self selectedBuildConfigurationOptionNames] objectAtIndex:row]];
	}
	return nil;
}

- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
	if ([[tableColumn identifier] isEqualToString:kWCBuildTargetGetInfoBuildOptionsValueColumnIdentifier]) {
		[[self selectedBuildConfiguration] setObjectValue:object forOptionName:[[self selectedBuildConfigurationOptionNames] objectAtIndex:row]];
	}
}
#pragma mark -
#pragma mark *** Public Methods ***
#pragma mark Creation
+ (WCBuildTargetGetInfoWindowController *)getInfoWindowControllerWithBuildTarget:(WCBuildTarget *)buildTarget; {
	return [[[[self class] alloc] initWithBuildTarget:buildTarget] autorelease];
}

- (id)initWithBuildTarget:(WCBuildTarget *)buildTarget; {
	if (!(self = [super initWithWindowNibName:@"WCBuildTargetGetInfoWindow"]))
		return nil;
	
	_buildTarget = [buildTarget retain];
	
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_buildTargetNameDidChangeNotification:) name:kWCBTBuildTargetNameDidChangeNotification object:_buildTarget];
	
	return self;
}
#pragma mark Accessors
@synthesize buildTarget=_buildTarget,selectedBuildConfigurationOptionNames=_selectedBuildConfigurationOptionNames,tabView=_tabView,buildStepsTableView=_buildStepsTableView;

@dynamic project;
- (WCProject *)project {
	return (WCProject *)[self document];
}
	
@dynamic selectedBuildConfiguration;
- (WCBuildConfiguration *)selectedBuildConfiguration {
	return [[_configurationPopUpButton selectedItem] representedObject];
}
#pragma mark IBActions
- (IBAction)modelPopUpButtonAction:(id)sender; {
	if ([_modelPopUpButton selectedTag] == [[self buildTarget] targetModel])
		return;	
	else if ([[self project] buildTargetExistsWithModel:[_modelPopUpButton selectedTag] output:[_outputPopUpButton selectedTag]]) {
		NSString *message = NSLocalizedString(@"Selected Build Target Already Exists",@"duplicate build target alert title");
		NSString *format = NSLocalizedString(@"A build target with the same target model and output already exists in the current project. You cannot have two build targets with the same target model and output.",@"body text for duplicate build target alert");
		NSAlert *alert = [NSAlert alertWithMessageText:message defaultButton:NSLocalizedButtonOK alternateButton:nil otherButton:nil informativeTextWithFormat:format];
		[alert beginSheetModalForWindow:[self window] modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
		[_modelPopUpButton selectItemWithTag:[[self buildTarget] targetModel]];
		return;
	}
	
	// remove all the current items
	[_outputPopUpButton removeAllItems];
	
	// set up the target output type pop up button
	for (NSDictionary *oDict in [[_modelPopUpButton selectedItem] representedObject]) {
		NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:[oDict objectForKey:@"name"] action:[_outputPopUpButton action] keyEquivalent:@""] autorelease];
		[item setTag:[oDict unsignedIntegerForKey:@"output"]];
		[[_outputPopUpButton menu] addItem:item];
	}
	[[self buildTarget] setTargetModel:[_modelPopUpButton selectedTag]];
}

- (IBAction)outputPopUpButtonAction:(id)sender; {
	if ([_outputPopUpButton selectedTag] == [[self buildTarget] targetOutputType])
		return;
	else if ([[self project] buildTargetExistsWithModel:[_modelPopUpButton selectedTag] output:[_outputPopUpButton selectedTag]]) {
		[_outputPopUpButton selectItemWithTag:[[self buildTarget] targetOutputType]];
		NSString *message = NSLocalizedString(@"Selected Build Target Already Exists",@"duplicate build target alert title");
		NSString *format = NSLocalizedString(@"A build target with the same target model and output already exists in the current project. You cannot have two build targets with the same target model and output.",@"body text for duplicate build target alert");
		NSAlert *alert = [NSAlert alertWithMessageText:message defaultButton:NSLocalizedButtonOK alternateButton:nil otherButton:nil informativeTextWithFormat:format];
		[alert beginSheetModalForWindow:[self window] modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
		return;
	}
	
	[[self buildTarget] setTargetOutputType:[_outputPopUpButton selectedTag]];
}

- (IBAction)configurationPopUpButtonAction:(id)sender; {
	[_buildOptionsTableView reloadData];
}

- (IBAction)editBuildOptionAction:(id)sender; {
	[_buildOptionsTableView sendAction:[_buildOptionsTableView doubleAction] to:self];
}

- (IBAction)addBuildStepAction:(id)sender; {
	[WCNewStepSheetController presentAddStepSheetForBuildTarget:[self buildTarget] forGetInfoWindowController:self];
}

- (IBAction)removeBuildStepAction:(id)sender; {
	if ([_buildStepsTableView selectedRow] == -1) {
		NSBeep();
		return;
	}
	
	WCBuildStep *step = [[[_buildStepsTableView dataSource] selectedObjects] firstObject];
	
	NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Delete Build Step \"%@\"",@"delete build step alert title"), [step name]];
	NSString *format = NSLocalizedString(@"Are you sure you want to delete this build step?",@"delete build step alert message");
	NSAlert *alert = [NSAlert alertWithMessageText:message defaultButton:NSLocalizedString(@"Delete Step",@"Delete Step") alternateButton:NSLocalizedButtonCancel otherButton:nil informativeTextWithFormat:format];
	
	[alert setAlertStyle:NSCriticalAlertStyle];
	
	[alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(_deleteStepAlertDidEnd:code:info:) contextInfo:NULL];
}

- (IBAction)editBuildStepAction:(id)sender; {
	if ([_buildStepsTableView selectedRow] == -1) {
		NSBeep();
		return;
	}
	
	[WCNewStepSheetController presentEditStepSheetForBuildTarget:[self buildTarget] originalBuildStep:[[[_buildStepsTableView dataSource] selectedObjects] firstObject] forGetInfoWindowController:self];
}

- (IBAction)addBuildConfigurationAction:(id)sender; {
	WCBuildConfiguration *config = [WCBuildConfiguration buildConfigWithName:NSLocalizedString(@"New Configuration",@"New Configuration") forBuildTarget:[self buildTarget]];
	
	if (NSUserDefaultsBoolForKey(kWCPrefsNewConfigurationCopyActiveConfigurationsDefinesToNewConfigurationKey)) {
		NSMutableArray *defines = [NSMutableArray array];
		
		for (WCBuildDefine *define in [[[self buildTarget] activeBuildConfiguration] defines]) {
			[defines addObject:[[define copy] autorelease]];
		}
		
		[config setDefines:defines];
	}
	
	if (NSUserDefaultsBoolForKey(kWCPrefsNewConfigurationCopyActiveConfigurationsIncludeDirectoriesToNewConfigurationKey)) {
		NSMutableArray *includes = [NSMutableArray array];
		
		for (WCBuildDefine *include in [[[self buildTarget] activeBuildConfiguration] includeDirectories]) {
			[includes addObject:[[include copy] autorelease]];
		}
		
		[config setIncludeDirectories:includes];
	}
	
	[[_configurationsTableView dataSource] addObject:config];
	[[_configurationsTableView dataSource] setSelectedObject:config];
	[_configurationsTableView editColumn:0 row:[_configurationsTableView selectedRow] withEvent:nil select:YES];
	
	[self _updateConfigurationsPopUpButton];
}

- (IBAction)removeBuildConfigurationAction:(id)sender; {
	WCBuildConfiguration *config = [[[_configurationsTableView dataSource] selectedObjects] firstObject];
	
	if ([config isConfigurationActive]) {
		NSBeep();
		return;
	}
	
	NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Delete Build Configuration \"%@\"",@"delete build configuration alert title"), [config name]];
	NSString *format = NSLocalizedString(@"Are you sure you want to delete this build configuration?",@"delete build configuration alert message");
	NSAlert *alert = [NSAlert alertWithMessageText:message defaultButton:NSLocalizedString(@"Delete Configuration",@"Delete Configuration") alternateButton:NSLocalizedButtonCancel otherButton:nil informativeTextWithFormat:format];
	
	[alert setAlertStyle:NSCriticalAlertStyle];
	
	[alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(_deleteAlertDidEnd:code:info:) contextInfo:NULL];
}

- (IBAction)duplicateBuildConfigurationAction:(id)sender; {
	WCBuildConfiguration *config = [[[[self buildTarget] activeBuildConfiguration] mutableCopy] autorelease];
	[config setName:[NSString stringWithFormat:NSLocalizedString(@"%@ Copy",@"duplicate build configuration name"),[config name]]];
	[[_configurationsTableView dataSource] addObject:config];
	[[_configurationsTableView dataSource] setSelectedObject:config];
	[_configurationsTableView editColumn:0 row:[_configurationsTableView selectedRow] withEvent:nil select:YES];
	
	[self _updateConfigurationsPopUpButton];
}

- (IBAction)makeActiveBuildConfigurationAction:(id)sender; {
	if ([_configurationsTableView selectedRow] == -1)
		return;
	
	WCBuildConfiguration *config = [[[_configurationsTableView dataSource] selectedObjects] firstObject];
	if ([[self buildTarget] isTargetActive])
		[[self project] setActiveBuildConfiguration:config];
	else
		[[self buildTarget] setActiveBuildConfiguration:config];
}
#pragma mark -
#pragma mark *** Private Methods ***
- (void)_updateConfigurationsPopUpButton; {
	WCBuildConfiguration *config = [self selectedBuildConfiguration];
	
	[_configurationPopUpButton removeAllItems];
	
	// set up the configurations pop up button
	for (WCBuildConfiguration *config in [[self buildTarget] buildConfigurations]) {
		NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:[config name] action:[_configurationPopUpButton action] keyEquivalent:@""] autorelease];
		[item setImage:[config icon]];
		[item setRepresentedObject:config];
		[[_configurationPopUpButton menu] addItem:item];
	}
	[_configurationPopUpButton selectItemWithRepresentedObject:config];
	
	[_configurationsTableView setNeedsDisplay:YES];
}
#pragma mark IBActions
- (IBAction)_buildOptionsTableViewDoubleAction:(id)sender {
	if ([_buildOptionsTableView selectedRow] == -1)
		return;
	
	if ([[self tableView:_buildOptionsTableView objectValueForTableColumn:[[_buildOptionsTableView tableColumns] firstObject] row:[_buildOptionsTableView selectedRow]] isEqualToString:kWCBCIncludeDirectoriesOptionName]) {
		[WCEditIncludeDirectoriesSheetController presentEditIncludeDirectoriesSheetForBuildConfiguration:[self selectedBuildConfiguration] forGetInfoWindowController:self];
	}
	else if ([[self tableView:_buildOptionsTableView objectValueForTableColumn:[[_buildOptionsTableView tableColumns] firstObject] row:[_buildOptionsTableView selectedRow]] isEqualToString:kWCBCDefinesOptionName]) {
		[WCEditDefinesSheetController presentEditDefinesSheetForBuildConfiguration:[self selectedBuildConfiguration] forGetInfoWindowController:self];
	}
}

- (void)_buildStepsTableViewDoubleAction:(id)sender; {
	[self editBuildStepAction:nil];
}
#pragma mark Callbacks
- (void)_deleteAlertDidEnd:(NSAlert *)alert code:(NSInteger)code info:(void *)info {
	if (code != NSAlertDefaultReturn)
		return;
	
	[[_configurationsTableView dataSource] remove:nil];
	
	[self _updateConfigurationsPopUpButton];
}

- (void)_deleteStepAlertDidEnd:(NSAlert *)alert code:(NSInteger)code info:(void *)info {
	if (code != NSAlertDefaultReturn)
		return;
	
	[[_buildStepsTableView dataSource] remove:nil];
}
#pragma mark Notifications
- (void)_activeBuildConfigurationDidChangeNotification:(NSNotification *)note {
	[self _updateConfigurationsPopUpButton];
}

- (void)_buildConfigurationNameDidChangeNotification:(NSNotification *)note {
	[self _updateConfigurationsPopUpButton];
}

- (void)_buildTargetNameDidChangeNotification:(NSNotification *)note {
	[self synchronizeWindowTitleWithDocumentName];
}
@end
